package com.zzj.controller;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.zzj.base.Result;
import com.zzj.entity.NurseSchedule;
import com.zzj.model.dto.QueryListDTO;
import com.zzj.model.dto.schedule.ScheduleAddDTO;
import com.zzj.model.dto.schedule.ScheduleBetweenDTO;
import com.zzj.model.dto.schedule.ScheduleUpdateDTO;
import com.zzj.service.INurseScheduleService;
import com.zzj.service.RedisService;
import com.zzj.utils.JWTUtil;
import com.zzj.utils.QueryUtil;
import com.zzj.utils.RedisUtil;
import com.zzj.utils.Utils;
import jakarta.annotation.Resource;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import java.util.List;
import java.util.Objects;
import java.util.function.Consumer;
import java.util.stream.Collectors;

/**
 * <p>
 * 医护排班 前端控制器
 * </p>
 *
 * @author zzj
 * @since 2023-02-24
 */
@RestController
@RequestMapping("/schedule")
public class NurseScheduleController {

    @Resource
    private INurseScheduleService nurseScheduleService;

    @Resource
    private RedisService redisService;


    /**
     * 获取 医护排班列表
     *
     * @param in
     * @return
     */
    @Transactional
    @PostMapping("list")
    public Result list(@RequestBody @Validated QueryListDTO in) {
        QueryWrapper<NurseSchedule> queryWrapper = QueryUtil.paramsWrapper(in.getAndParams(), in.getOrParams(), in.getOrderParams());
        Page<NurseSchedule> nurseSchedulePage = new Page<>(in.getPageNo(), in.getPageSize());
        IPage<NurseSchedule> nurseScheduleIPage = nurseScheduleService.getBaseMapper().selectPage(nurseSchedulePage, queryWrapper);
        return Result.success(nurseScheduleIPage);
    }

    // 添加医护排班
    @Transactional
    @PostMapping("add")
    public Result add(@RequestBody @Validated ScheduleAddDTO in) {
        List<NurseSchedule> list = nurseScheduleService.lambdaQuery()
                .between(NurseSchedule::getStart, in.getStart(), in.getEnd())
                .or().between(NurseSchedule::getEnd, in.getStart(), in.getEnd())
                .or(i -> i.ge(NurseSchedule::getEnd, in.getEnd()).le(NurseSchedule::getStart, in.getStart()))
                .list();
        for (NurseSchedule nurseSchedule : list) {
            if (Objects.equals(nurseSchedule.getUsername(), in.getUsername())) {
                return Result.error("排班失败，该时间段已有排班");
            }
        }
        NurseSchedule nurseSchedule = JSONObject.parseObject(JSONObject.toJSONString(in), NurseSchedule.class);
        nurseScheduleService.save(nurseSchedule);
        return Result.success("排班成功");
    }

    // 修改医护排班
    @PostMapping("update")
    public Result update(@RequestBody @Validated ScheduleUpdateDTO in) {
        List<NurseSchedule> list = nurseScheduleService.lambdaQuery()
                .between(NurseSchedule::getStart, in.getStart(), in.getEnd())
                .or().between(NurseSchedule::getEnd, in.getStart(), in.getEnd())
                .or(i -> i.ge(NurseSchedule::getEnd, in.getEnd()).le(NurseSchedule::getStart, in.getStart()))
                .list();
        for (NurseSchedule nurseSchedule : list) {
            if(nurseSchedule.getId()==in.getId())continue;
            if (Objects.equals(nurseSchedule.getUsername(), in.getUsername())) {
                return Result.error("排班失败，该时间段已有排班");
            }
        }
        NurseSchedule nurseSchedule = JSONObject.parseObject(JSONObject.toJSONString(in), NurseSchedule.class);
        nurseScheduleService.updateById(nurseSchedule);
        return Result.success("修改成功");
    }

    // 删除医护排班
    @PostMapping("remove")
    public Result remove(@RequestParam int id) {
        nurseScheduleService.removeById(id);
        return Result.success("删除成功");
    }

    // 获取指定时间范围内的医护排班
    @PostMapping("between")
    public Result between(@RequestBody @Validated ScheduleBetweenDTO in) {
        LambdaQueryWrapper<NurseSchedule> queryWrapper = new LambdaQueryWrapper<>();
        Consumer<LambdaQueryWrapper<NurseSchedule>> lambdaQueryWrapperConsumer = LambdaBetweenConsumer(in.getStart(), in.getEnd());
        queryWrapper.and(lambdaQueryWrapperConsumer).orderByAsc(NurseSchedule::getStart);
        Page<NurseSchedule> nurseSchedulePage = new Page<>(in.getPageNo(), in.getPageSize());
        IPage<NurseSchedule> iNurseSchedulePage = nurseScheduleService.getBaseMapper().selectPage(nurseSchedulePage, queryWrapper);
        return Result.success(iNurseSchedulePage);
    }

    // 获取自己在指定时间范围内的医护排班
    @PostMapping("betweenSelf")
    public Result betweenSelf(@RequestHeader(value = "Authorization") String token,
                              @RequestBody @Validated ScheduleBetweenDTO in) {
        String username = JWTUtil.getUsername(token);
        LambdaQueryWrapper<NurseSchedule> queryWrapper = new LambdaQueryWrapper<>();
        Consumer<LambdaQueryWrapper<NurseSchedule>> lambdaQueryWrapperConsumer = LambdaBetweenConsumer(in.getStart(), in.getEnd());
        queryWrapper
                .eq(NurseSchedule::getUsername, username)
                .and(lambdaQueryWrapperConsumer)
                .orderByAsc(NurseSchedule::getStart)
                .orderByAsc(NurseSchedule::getEnd);
        Page<NurseSchedule> nurseSchedulePage = new Page<>(in.getPageNo(), in.getPageSize());
        IPage<NurseSchedule> iNurseSchedulePage = nurseScheduleService.getBaseMapper().selectPage(nurseSchedulePage, queryWrapper);
        return Result.success(iNurseSchedulePage);
    }

    // 获取指定时间范围内的医护排班
    @PostMapping("patientBetween")
    public Result patientBetween(@RequestHeader(value = "Authorization") String token,
                                 @RequestBody @Validated ScheduleBetweenDTO in) {
        Consumer<QueryWrapper<NurseSchedule>> lambdaQueryWrapperConsumer = betweenConsumer(in.getStart(), in.getEnd());
        QueryWrapper<NurseSchedule> queryWrapper = QueryUtil.paramsWrapper(in.getAndParams(), in.getOrParams(), in.getOrderParams());
        queryWrapper.and(lambdaQueryWrapperConsumer);
        Page<NurseSchedule> nurseSchedulePage = new Page<>(in.getPageNo(), in.getPageSize());
        IPage<NurseSchedule> iNurseSchedulePage = nurseScheduleService.getBaseMapper().selectPage(nurseSchedulePage, queryWrapper);
        List<NurseSchedule> schedules = iNurseSchedulePage.getRecords();
        String username = JWTUtil.getUsername(token);
        String scheduleId = redisService.getBookScheduleId(username);
        if (scheduleId != null && !scheduleId.equals("")) {
            List<String> reads = Utils.stringToList(scheduleId, ",");
            List<NurseSchedule> list = setIsAppointment(schedules, reads);
            iNurseSchedulePage.setRecords(list);
        }
        return Result.success(iNurseSchedulePage);
    }

    // Lambda表达式构建查询条件：指定时间范围内的排班
    private Consumer<LambdaQueryWrapper<NurseSchedule>> LambdaBetweenConsumer(String start, String end) {
        Consumer<LambdaQueryWrapper<NurseSchedule>> wrapperConsumer = nurseScheduleQueryWrapper -> {
            nurseScheduleQueryWrapper
                    .between(NurseSchedule::getStart, start, end)
                    .or().between(NurseSchedule::getEnd, start, end)
                    .or(i -> {
                        i.lt(NurseSchedule::getStart, start)
                                .gt(NurseSchedule::getEnd, end);
                    });
        };
        return wrapperConsumer;
    }

    // 构建查询条件：指定时间范围内的排班
    private Consumer<QueryWrapper<NurseSchedule>> betweenConsumer(String start, String end) {
        Consumer<QueryWrapper<NurseSchedule>> wrapperConsumer = nurseScheduleQueryWrapper -> {
            nurseScheduleQueryWrapper
                    .between("start", start, end)
                    .or().between("end", start, end)
                    .or(i -> {
                        i.lt("start", start)
                                .gt("end", end);
                    });
        };
        return wrapperConsumer;
    }


    /**
     * 预约
     * 两列表合并
     * 设置是否已预约的标志位
     *
     * @param schedules
     * @param idList
     * @return
     */
    private List<NurseSchedule> setIsAppointment(List<NurseSchedule> schedules, List<String> idList) {
        return schedules.stream()
                .map(schedule -> idList.stream()
                        .filter(str -> schedule.getId() == Integer.parseInt(str))
                        .findFirst()
                        .map(str -> {
                            schedule.setIsAppointment(1);
                            return schedule;
                        }).orElse(schedule)).collect(Collectors.toList());
    }
}
